package game.module.user.dao;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.ResultSetHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import game.common.DaoCommonHandler;
import game.db.DataSourceManager;
import game.lan.bean.GarenaLoginSessionBean;
import game.lan.bean.LoginSessionBean;
import game.lan.bean.QqLoginSessionBean;
import game.lan.bean.SifubaLoginSessionBean;
import game.module.user.bean.PlayerBean;

public class PlayerDao {

	private static Logger logger = LoggerFactory.getLogger(PlayerDao.class);

	private DataSource dataSource = DataSourceManager.getInstance().getDataSource();

	static class SingletonHolder {
		static PlayerDao instance = new PlayerDao();
	}

	public static PlayerDao getInstance() {
		return SingletonHolder.instance;
	}

	/**
	 * 
	 */
	private ResultSetHandler<PlayerBean> aPlayerHandler = new ResultSetHandler<PlayerBean>() {
		@Override
		public PlayerBean handle(ResultSet rs) throws SQLException {
			PlayerBean playerBean = null;
			if (rs.next()) {
				playerBean = new PlayerBean();
				playerBean.setId(rs.getInt("id"));
				playerBean.setAccountId(rs.getString("account_id"));
				playerBean.setName(rs.getString("name"));
				playerBean.setSex(rs.getInt("sex"));
				playerBean.setHeadimg(rs.getString("headimg"));
				playerBean.setLevel(rs.getInt("level"));
				playerBean.setLevel_exp(rs.getInt("level_exp"));
				playerBean.setCoins(rs.getInt("coins"));
				playerBean.setYuan_bao(rs.getInt("yuan_bao"));
				playerBean.setFang_ka(rs.getInt("fang_ka"));
				playerBean.setCreate_time(rs.getTimestamp("create_time"));
				playerBean.setDownlineTime(rs.getTimestamp("downline_time"));
			}
			return playerBean;
		}
	};

	private ResultSetHandler<List<PlayerBean>> multiPlayerHandler = new ResultSetHandler<List<PlayerBean>>() {
		@Override
		public List<PlayerBean> handle(ResultSet rs) throws SQLException {
			List<PlayerBean> userBeanList = new ArrayList<PlayerBean>();
			while (rs.next()) {
				PlayerBean playerBean = new PlayerBean();
				playerBean.setId(rs.getInt("id"));
				playerBean.setAccountId(rs.getString("account_id"));
				playerBean.setName(rs.getString("name"));
				playerBean.setSex(rs.getInt("sex"));
				playerBean.setHeadimg(rs.getString("headimg"));
				playerBean.setLevel(rs.getInt("level"));
				playerBean.setLevel_exp(rs.getInt("level_exp"));
				playerBean.setCoins(rs.getInt("coins"));
				playerBean.setYuan_bao(rs.getInt("yuan_bao"));
				playerBean.setFang_ka(rs.getInt("fang_ka"));
				playerBean.setCreate_time(rs.getTimestamp("create_time"));
				playerBean.setDownlineTime(rs.getTimestamp("downline_time"));
				userBeanList.add(playerBean);
			}
			return userBeanList;
		}
	};

	public boolean checkExistByUserName(String userName) {
		boolean ret = false;
		ResultSetHandler<Boolean> handler = new ResultSetHandler<Boolean>() {
			@Override
			public Boolean handle(ResultSet rs) throws SQLException {
				int retFlag = 0;
				if (rs.next()) {
					retFlag = rs.getInt(1);
				}
				return retFlag > 0 ? true : false;
			}
		};
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT EXISTS(select 1 from player where name = ?)", handler, userName);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public PlayerBean getPlayerById(int playerId) {
		PlayerBean ret = null;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player where id = ?", aPlayerHandler, playerId);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public PlayerBean getPlayerByName(String userName) {
		PlayerBean ret = null;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player where name = ?", aPlayerHandler, userName);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public List<PlayerBean> getPlayersByPlatfrom(LoginSessionBean lsb) {
		if (lsb instanceof GarenaLoginSessionBean) {
			return getPlayerByOpenId(((GarenaLoginSessionBean) lsb).getGarenaOpenId(), lsb.getServerId());
		} else if (lsb instanceof SifubaLoginSessionBean) {
			return getPlayerByOpenId(((SifubaLoginSessionBean) lsb).getUserId(), lsb.getServerId());
		} else if (lsb instanceof QqLoginSessionBean) {
			return getPlayerByOpenId(((QqLoginSessionBean) lsb).getOpenId(), lsb.getServerId());
		} else {
			return getPlayerByOpenId(String.valueOf(lsb.getUid()), lsb.getServerId());
		}
	}

	public int getFeedbackCount(String openId) {
		int ret = 0;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT add_point from topup_feedback where open_id = ? and type = 0 and status = 0",
					DaoCommonHandler.Integerhandler, openId);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public List<PlayerBean> getPlayerByOpenId(String openId, int serverId) {
		List<PlayerBean> ret = null;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player where account_id = ?", multiPlayerHandler,
					openId);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public List<PlayerBean> getAllPlayers() {
		List<PlayerBean> ret = null;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player", multiPlayerHandler);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public boolean addUser(PlayerBean pb) {
		boolean addRet = false;
		QueryRunner runner = new QueryRunner(dataSource);
		Connection conn = null;
		try {
			conn = dataSource.getConnection();
			int ret = runner.update(conn,
					"insert into player(account_id,name,sex,headimg,level,level_exp,coins,yuan_bao,fang_ka,create_time) "
							+ "values(?,?,?,?,?,?,?,?,?,NOW())",
					pb.getAccountId(), pb.getName(), pb.getSex(), pb.getHeadimg(), pb.getLevel(), pb.getLevel_exp(),
					pb.getCoins(), pb.getYuan_bao(), pb.getFang_ka());
			if (ret > 0) {
				addRet = true;
			}
			if (addRet) {
				int theId = runner.query(conn, "SELECT LAST_INSERT_ID();", DaoCommonHandler.Integerhandler);
				pb.setId(theId);
			}
		} catch (SQLException e) {
			logger.error("", e);
		} finally {
			DbUtils.closeQuietly(conn);
		}
		return addRet;
	}

	public void updateVipLev(int newVipLev, int newVipExp, int playerId) {
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			runner.update("update player set vip_level = ?, vip_exp = ? where id = ?", newVipLev, newVipExp, playerId);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	public List<PlayerBean> getUserByUids(String uidAllStr) {
		List<PlayerBean> ret = null;

		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from user where id in (?)", multiPlayerHandler, uidAllStr);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public boolean updatePlayerBean(PlayerBean playerBean) {
		boolean addRet = false;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			runner.update(
					"update player set name=?,sex=?,headimg=?,level=?,level_exp=?,coins=?,yuan_bao=?,fang_ka=?,downline_time=? where id = ?",
					playerBean.getName(), playerBean.getSex(), playerBean.getHeadimg(), playerBean.getLevel(),
					playerBean.getLevel_exp(), playerBean.getCoins(), playerBean.getYuan_bao(), playerBean.getFang_ka(),
					playerBean.getDownlineTime(), playerBean.getId());
		} catch (SQLException e) {
			logger.error("", e);
		}
		return addRet;
	}

	public void updateGarenaLoginInfo(String gaAccessToken, String gaOpenId, int playerId) {
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			runner.update("update player set ga_access_token=?,ga_open_id = ? where id = ?", gaAccessToken, gaOpenId,
					playerId);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	public List<PlayerBean> getPlayersForOffline(int MAX_PLAYER_CACHE_SIZE) {
		List<PlayerBean> ret = null;

		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player order by level desc limit ?", multiPlayerHandler,
					(int) (MAX_PLAYER_CACHE_SIZE * 0.5));
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public List<PlayerBean> rankPlayerLevel() {
		List<PlayerBean> ret = null;

		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player order by level desc,upgrade_time desc limit ?", multiPlayerHandler,
					15000);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public List<Integer> rankPlayerLevelMy() {
		List<Integer> ret = null;

		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT id from player order by level desc,upgrade_time desc",
					DaoCommonHandler.IntegerListHandler);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

	public void updateName(String newName, int playerId) {
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			runner.update("update player set name = ? where id = ?", newName, playerId);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	public void addMoney(int addDiamond, String openId) {
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			runner.update("update player set money = money + ? where account_id = ?", addDiamond, openId);
		} catch (SQLException e) {
			logger.error("", e);
		}
	}

	public List<PlayerBean> searchPlayerByName(String playerName) {
		List<PlayerBean> ret = null;
		QueryRunner runner = new QueryRunner(dataSource);
		try {
			ret = runner.query("SELECT * from player where name like ? order by level desc,create_time desc limit ?",
					multiPlayerHandler, "%" + playerName + "%", 10);
		} catch (SQLException e) {
			logger.error("", e);
			return ret;
		}
		return ret;
	}

}
